package com.hezhiqin.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @program: homeWork
 * @description:
 * @author: hezhiqin
 * @create: 2020-03-30 15:24
 */
public class NIOServerDemo {
    private  int port ;
    //准备两个东西
    //1轮询器
    private Selector  selector;
    //2缓冲区
    private ByteBuffer byteBuffer = ByteBuffer.allocate(2048);

    //初始化
    public NIOServerDemo(int port) {
        try {
            this.port = port;
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //开放一个地址
            serverSocketChannel.bind(new InetSocketAddress(port));
            //升级为Nio
            serverSocketChannel.configureBlocking(false);
            //轮询器就绪 经理开始工作
            selector = Selector.open();

            //开始营业
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        }catch (Exception e){
            e.printStackTrace();
        }


    }


    public  void listen(){
        System.out.println("listen on this" + port +":");
        //轮询主线程
        while (true){
            try {
                //大堂经理叫好
                selector.select();
                //每次都拿到所有的号子
                Set<SelectionKey> selectionKeys =  selector.selectedKeys();
                System.out.println(selectionKeys.isEmpty()+":"+selectionKeys.size());
                Iterator<SelectionKey> iter = selectionKeys.iterator();
                while (iter.hasNext()){
                    SelectionKey key = iter.next();
                    iter.remove();
                    //每一个key代表一种状态
                    //没一个号对应一个业务
                    //数据就绪、数据可读、数据可写 等等等等
                    process(key);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //处理业务的办法
    //每一次轮询都是调用一个process方法，每次调用只能干一件事
    //确认状态后等待下次轮询
    private void process(SelectionKey selectionKey) throws IOException {

        if (selectionKey.isAcceptable()){
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectionKey.channel();
            SocketChannel socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            //当数据准备好了就吧状态改成可读
            socketChannel.register(selector,SelectionKey.OP_READ);
        }else  if (selectionKey.isReadable()){
            //从多路复用器中拿到客户端的应用
            SocketChannel socketChannel =   (SocketChannel)selectionKey.channel();
             int length = socketChannel.read(byteBuffer);
             if (length>0){
                 byteBuffer.flip();
                 String content = new String(byteBuffer.array(),0,length);
                 selectionKey = socketChannel.register(selector,SelectionKey.OP_WRITE);
                 //在key上携带一个附件，一会再写出去
                 selectionKey.attach("收到了"+content);
                 System.out.println("读取内容：" + content);
             }

        } else if(selectionKey.isWritable()){
            SocketChannel channel = (SocketChannel)selectionKey.channel();
            String content = (String)selectionKey.attachment();
            channel.write(ByteBuffer.wrap(("输出：" + content).getBytes()));
            channel.close();
        }



    }


    public static void main(String[] args) {
        new NIOServerDemo(3000).listen();
    }
}
